﻿namespace MeTool.BarCode
{
    /// <summary>
    /// 用于对Code93码的操作,线数=码数*9+37,于58小票机上可显示10个字符
    /// </summary>
    /// <remarks>Code39码:由数字 和 英文字母 和 + - * / % $ 和 小数点 和 空格 组成. 18位单据号:由18个数字组成. 压缩字码:由18位单据号压缩成的12位Code39码</remarks>
    public static class Code93
    {
        /// <summary>
        /// 返回指定的Code93码的线码,Code93码的码元可以是数字也可以是英文字母,另外还包括 + - * / % $ 以及小数点和空格
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string GetLine(string code93Text)
        {
            if (code93Text == null || code93Text.Length < 2) return "";
            string dLine = "101011110";
            int dLength = code93Text.Length;
            int dCheckC = 0;
            int dCheckK = 0;
            int num = dLength - 1;
            for (int xx = 0; xx <= num; xx++)
            {
                int dIndex = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%()#@*".IndexOf(code93Text[xx]);
                if (dIndex == -1) return "";

                dLine += mLines[dIndex];
                dCheckC += (dLength - xx) % 20 * dIndex;
                dCheckK += (dLength - xx + 1) % 15 * dIndex;
            }
            dCheckC %= 47;
            dCheckK = (dCheckK + dCheckC) % 47;
            dLine += mLines[dCheckC];
            dLine += mLines[dCheckK];
            dLine += "1010111101";
            return dLine;
        }

        /// <summary>
        /// 使用行图模式生成条码打印指令
        /// </summary>
        /// <param name="code93Text"></param>
        /// <param name="rowCount"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string GetPosImageRow(string code93Text, int rowCount = 4)
        {
            if (code93Text.Length == 0) return "";

            string dLine = GetLine(code93Text);
            if (dLine.Length == 0) return "";

            int dLeft = (384 - dLine.Length * 3) / 2;
            if (dLeft < 0) return "";

            string dCode = "";
            for (var yy = 1; yy <= rowCount; yy++)
            {
                dCode += "\u001b3\u0018";
                dCode = dCode + "\u001b*\u0001" + ((char)((dLine.Length * 3 + dLeft) % 256)).ToString() + ((char)((dLine.Length * 3 + dLeft) / 256)).ToString();
                dCode += new string('\0', dLeft);
                int num = dLine.Length - 1;
                for (var xx = 0; xx <= num; xx++)
                {
                    if (dLine[xx] == '1')
                    {
                        dCode += new string((char)255, 3);
                    }
                    else
                    {
                        dCode += new string('\0', 3);
                    }
                }
                dCode += "\u001b2";
                if (yy == 1)
                {
                    dCode = dCode + "\r\n" + POS.CenterText(code93Text, 32, false) + "\r\n";
                }
            }
            return dCode;
        }

        /// <summary>
        /// 使用小票机内建支持的格式生成条码打印指令
        /// </summary>
        /// <param name="code93Text"></param>
        /// <param name="rowCount"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string GetPosInner(string code93Text, int rowCount = 4)
        {
            var dLine = GetLine(code93Text);
            if (dLine.Length == 0) return "";

            var dLeft = (384 - dLine.Length * 3) / 2;
            if (dLeft < 0) return "";

            var dText = "";
            dText += "\u001dh\u0018";
            dText = dText + "\u001dL" + ((char)(dLeft % 256)).ToString() + ((char)(dLeft / 256)).ToString();
            dText = dText + "\u001dkH" + ((char)code93Text.Length).ToString();
            dText += code93Text;
            dText += "\u001dL\0\0";
            dText = dText + POS.CenterText(code93Text, 32, false) + "\r\n";
            if (rowCount - 1 > 0)
            {
                dText = dText + "\u001dL" + ((char)(dLeft % 256)).ToString() + ((char)(dLeft / 256)).ToString();
                dText = dText + "\u001dh" + ((char)(24 * (rowCount - 1))).ToString();
                dText = dText + "\u001dkH" + ((char)code93Text.Length).ToString();
                dText += code93Text;
                dText += "\u001dL\0\0";
            }
            return dText;
        }

        /// <summary>
        /// 使用列图模式生成条码打印指令
        /// </summary>
        /// <param name="code93Text"></param>
        /// <param name="rowCount"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string GetPosImageCol(string code93Text, int rowCount = 4)
        {
            var dLine = GetLine(code93Text);
            if (dLine.Length == 0) return "";

            var dLeft = (384 - dLine.Length * 3) / 2;
            if (dLeft < 0) return "";

            var dRight = 8 - (dLine.Length * 3 + dLeft) % 8;
            var dCode = "\u001d*" + ((char)((dLeft + dLine.Length * 3 + dRight) / 8)).ToString() + "\u0003";
            dCode += new string('\0', 3 * dLeft);
            for (var xx = 0; xx < dLine.Length; xx++)
            {
                if (dLine[xx] == '1')
                {
                    dCode += new string((char)255, 9);
                }
                else
                {
                    dCode += new string('\0', 9);
                }
            }
            dCode += new string('\0', 3 * dRight);
            dCode += "\u001d/\0";
            dCode = dCode + POS.CenterText(code93Text, 32, false) + "\r\n";
            if (rowCount > 1)
            {
                dCode = dCode + "\u001d*" + ((char)((dLeft + dLine.Length * 3 + dRight) / 8)).ToString() + ((char)((rowCount - 1) * 3)).ToString();
                dCode += new string('\0', (rowCount - 1) * 3 * dLeft);
                for (var xx2 = 0; xx2 < dLine.Length; xx2++)
                {
                    if (dLine[xx2] == '1')
                    {
                        dCode += new string((char)255, (rowCount - 1) * 3 * 3);
                    }
                    else
                    {
                        dCode += new string('\0', (rowCount - 1) * 3 * 3);
                    }
                }
                dCode += new string('\0', (rowCount - 1) * 3 * dRight);
                dCode += "\u001d/\0";
            }
            return dCode;
        }

        /// <summary>
        /// 按顺序公布93码支持的所有字符
        /// </summary>
        /// <remarks></remarks>
        public const string Words = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%()#@*";

        private static readonly string[] mLines = new string[]
        {
            "100010100",
            "101001000",
            "101000100",
            "101000010",
            "100101000",
            "100100100",
            "100100010",
            "101010000",
            "100010010",
            "100001010",
            "110101000",
            "110100100",
            "110100010",
            "110010100",
            "110010010",
            "110001010",
            "101101000",
            "101100100",
            "101100010",
            "100110100",
            "100011010",
            "101011000",
            "101001100",
            "101000110",
            "100101100",
            "100010110",
            "110110100",
            "110110010",
            "110101100",
            "110100110",
            "110010110",
            "110011010",
            "101101100",
            "101100110",
            "100110110",
            "100111010",
            "100101110",
            "111010100",
            "111010010",
            "111001010",
            "101101110",
            "101110110",
            "110101110",
            "100100110",
            "111011010",
            "111010110",
            "100110010",
            "101011110"
        };
    }
}
